local vec2 = require 'vec2'

---@class constrained_size : constrained_size_mt
---@field width_unconstrained boolean
---@field height_unconstrained boolean
---@field width number
---@field height number
local constrained_size = {}

---@package
---@class constrained_size_mt
local mt
mt = {
    ---@param self constrained_size
    ---@param width number
    ---@param height number
    ---@return table
    __call = function(self, width, height)
        local c = {}
        setmetatable(c, mt)

        c.width_unconstrained = width == nil
        c.height_unconstrained = height == nil
        c.width = width or 0
        c.height = height or 0

        return c
    end,

    ---@param x constrained_size
    ---@param y constrained_size
    __eq = function(x, y)
        return
            (
                (x.width_unconstrained and y.width_unconstrained)
                or
                (
                    not (x.width_unconstrained or y.width_unconstrained) and
                    x.width == y.width
                )
            )
            and
            (
                (x.height_unconstrained and y.height_unconstrained)
                or
                (
                    not (x.height_unconstrained or y.height_unconstrained) and
                    x.height == y.height
                )
            )
    end
}

setmetatable(constrained_size, mt)
mt.__index = constrained_size

---@return constrained_size
function constrained_size.unconstrained()
    return constrained_size()
end

---@param v vec2
---@return constrained_size
function constrained_size.from_vec2(v)
    return constrained_size(v.x, v.y)
end

function constrained_size:to_vec2()
    assert(not self.width_unconstrained and not self.height_unconstrained)
    return vec2(self.width, self.height)
end

---@param fallback vec2
---@return vec2
function constrained_size:to_vec2_or(fallback)
    return vec2(
        self.width_unconstrained and fallback.x or self.width,
        self.height_unconstrained and fallback.y or self.height
    )
end

---@param value number
function constrained_size:set_constrained_width(value)
    self.width_unconstrained = false
    self.width = value
end

---@param value number
function constrained_size:set_constrained_height(value)
    self.height_unconstrained = false
    self.height = value
end

function constrained_size:set_unconstrained_width()
    self.width_unconstrained = false
end

function constrained_size:set_uncostrained_height()
    self.height_unconstrained = false
end

return constrained_size
